﻿using System;
using System.Collections;
using System.Threading;

namespace WFIM.Framework.Parellel
{
  /// <include file='XMLCodeDocumentation.xml' path='documentation/item[@name="T_ParallelDispatcher"]/*' />
  public class ParallelDispatcher : ParallelTaskManager
  {
    //-----------------------------------------------------------------------
    // FIELDS
    //-----------------------------------------------------------------------

    //-----------------------------------------------------------------------
    // CONSTRUCTORS
    //-----------------------------------------------------------------------
    protected ParallelDispatcher()
    {
    }

    //-----------------------------------------------------------------------
    // METHODS
    //-----------------------------------------------------------------------
    /// <summary>Runs a task for each element of a collection.</summary>
    /// <remarks>
    /// Takes a collection as input and creates and runs a task for each element of that collection. Passing the element as a parameter to the task. All tasks use the same state object.
    /// After the task has finished, the callback delegate is called.
    /// </remarks>
    /// <param name="_collection">The collection containing all the elements for which tasks are created and run.</param>
    /// <param name="_state">The state object which is passed to all tasks. All tasks share the same state object.</param>
    /// <param name="_runner">A delegate to the code that the task must execute.</param>
    /// <param name="_callback">A delegate to the code that is called when the task is done processing. The value may be <c>null</c>.</param>
    public static void dispatch(IEnumerable _collection, ParallelState _state, ParallelTask.TaskItemRunnerDelegate _runner, ParallelTask.TaskCallbackDelegate _callback)
    {
      //create parent callback
      ParallelTask.TaskParentCallback parentCallback = new ParallelTask.TaskParentCallback(endTask);

      //go through the whole collection
      foreach (object item in _collection)
      {
        //create a new task
        ParallelTask task = new ParallelTask(_runner, _state, item, parentCallback, _callback);

        //run the task
        if (!task.run())
          throw new TaskFailedToRunException(task);

        //count running tasks
        incrementTaskCounter();
      }
    }

    //-----------------------------------------------------------------------
    /// <summary>Runs a task for each element of a collection.</summary>
    /// <remarks>
    /// Takes a collection as input and creates and runs a task for each element of that collection. Passing the element as a parameter to the task. All tasks use the same state object.
    /// </remarks>
    /// <param name="_collection">The collection containing all the elements for which tasks are created and run.</param>
    /// <param name="_state">The state object which is passed to all tasks. All tasks share the same state object.</param>
    /// <param name="_runner">A delegate to the code that the task must execute.</param>
    public static void dispatch(IEnumerable _collection, ParallelState _state, ParallelTask.TaskItemRunnerDelegate _runner)
    {
      dispatch(_collection, _state, _runner, null);
    }

    //-----------------------------------------------------------------------
    private static void endTask(ParallelState _state)
    {
      decrementTaskCounter();
    }

    //-----------------------------------------------------------------------
  }
}
